package com.samp.lucene.core;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Calendar;
import java.util.Date;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoubleDocValuesField;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class IndexWriterDemo {
	
	public static void indexDocs(String indexPath, String docsPath, boolean create){
		try {
			Directory directory = FSDirectory.open(Paths.get(indexPath));
			///Analyzer analyzer = new StandardAnalyzer();
			Analyzer analyzer = new IKAnalyzer(true, true, false);
			IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
			if( create ){
				iwc.setOpenMode(OpenMode.CREATE);
			}else{
				iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
			}
			//很多文档时，可以设置ram参数。
			//iwc.setRAMBufferSizeMB(128.0);
			IndexWriter iw = new IndexWriter(directory, iwc);
			//将文档添加至索引。
			Path path = Paths.get(docsPath);
			if( Files.isDirectory(path)){
				Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
					@Override
					public FileVisitResult visitFile(Path file,BasicFileAttributes attrs) throws IOException {
						try{
							
							indexDoc(iw, file, attrs.lastModifiedTime().toMillis());
						}catch(Exception e){
							e.printStackTrace();
						}
						 return FileVisitResult.CONTINUE;
					}
					
				});
			}else{
				indexDoc(iw,path, Files.getLastModifiedTime(path).toMillis());
			}
		iw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	private static void indexDoc(IndexWriter iw, Path file, Long lastModified) throws Exception{
		Document doc = new Document();
		String contents = getContents(file);
		String[] splits = contents.split("\\|");
		Integer id = Integer.valueOf(splits[0])+1;
		String title = splits[1];
		String creator = splits[2];
		Date createTime = DateTools.stringToDate(splits[3]);
		Integer intNum = Integer.valueOf(splits[4]);
		Double doubleNum = Double.valueOf(splits[5]);
		System.out.println("add id  "+id);
		addValToDoc(doc,"id",id,true,true,true);
		System.out.println("add title  "+title);
		addValToDoc(doc,"title",title,true,true,true);
		System.out.println("add creator  "+creator);
		addValToDoc(doc,"creator",creator,true,true,true);
		System.out.println("add date  "+DateTools.dateToString(createTime, DateTools.Resolution.SECOND));
		addValToDoc(doc,"createTime",createTime,true,true,true);
		System.out.println("add intNum  "+intNum);
		addValToDoc(doc,"intNum",intNum,true,true,true);
		System.out.println("add doubleNum  "+doubleNum);
		addValToDoc(doc,"doubleNum",doubleNum,true,true,true);
		System.out.println("add lastModified  "+lastModified);
		addValToDoc(doc,"lastModified",lastModified,true,true,true);
		System.out.println("add path  "+file.toString());
		addValToDoc(doc,"path",file.toString(),true,true,true);
		if( iw.getConfig().getOpenMode().equals(OpenMode.CREATE) ){
			iw.addDocument(doc);
		}else{
			iw.updateDocument(new Term("path", file.toString()), doc);
		}
	}
	
	private static void addValToDoc(Document doc, String fieldName, Object val, boolean needIndex, 
							boolean needStore, boolean needSort) throws Exception{
		if( val instanceof Integer ){
			Integer integerVal = (Integer)val;
			if( needIndex ){
				doc.add( new IntPoint(fieldName,integerVal) );
			}
			if( needStore ){
				doc.add( new StoredField(fieldName,integerVal) );
			}
			if( needSort ){
				doc.add( new NumericDocValuesField(fieldName,integerVal) );
			}
		}else if( val instanceof String ){
			String objectVal = (String)val;
			//title 要分词，所以用TextField，不分词的用StringField
			if( "title".equals(fieldName) ){
				doc.add(new TextField(fieldName,objectVal, needStore?Store.YES:Store.NO));
			}else{
				doc.add(new StringField(fieldName,objectVal, needStore?Store.YES:Store.NO));
			}
		}else if( val instanceof Date ){
			Date objectVal = (Date)val;
			if( needIndex ){
				doc.add( new LongPoint(fieldName,objectVal.getTime()) );
			}
			if( needStore ){
				doc.add( new StoredField(fieldName,objectVal.getTime()) );
			}
			if( needSort ){
				doc.add( new NumericDocValuesField(fieldName,objectVal.getTime()) );
			}
		}else if( val instanceof Long ){
			Long objectVal = (Long)val;
			if( needIndex ){
				doc.add( new LongPoint(fieldName,objectVal) );
			}
			if( needStore ){
				doc.add( new StoredField(fieldName,objectVal) );
			}
			if( needSort ){
				doc.add( new NumericDocValuesField(fieldName,objectVal) );
			}
		}else if( val instanceof Double ){
			Double objectVal = (Double)val;
			if( needIndex ){
				doc.add( new DoublePoint(fieldName,objectVal) );
			}
			if( needStore ){
				doc.add( new StoredField(fieldName,objectVal) );
			}
			if( needSort ){
				doc.add( new DoubleDocValuesField(fieldName,objectVal) );
			}
		}
		else{
			throw new Exception("unsupport val type:"+val.getClass());
		}
	}
	
	private static String getContents(Path file) throws IOException{
		BufferedReader bufferReader = new BufferedReader(new InputStreamReader(Files.newInputStream(file), StandardCharsets.UTF_8));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while( (line = bufferReader.readLine()) != null ){
				sb.append(line);
			}
			bufferReader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	
	public static void generateTestData(String dataDir){
		//生成10个测试文件。
		//最开始第二个是：百度网盘，智能分词会分为：百度网，用百度查不出来
		//所以改成百度音箱
		//标题数组。
		String[] titleList = {"百度一下,你就知道","百度音箱,让美好永远陪伴",
									 "百度搜索资源平台_让网站更具价值","百度产品大全",
									 "百度知道 - 全球最大中文互动问答平台","百度_百度百科",
									 "百度浏览器-迅捷 精选 简约","百度指数",
									 "百度网址大全","百度图片-发现多彩世界"};
		String[] creatorList = {"张三丰","李四公","王五牛"};
		for( int i = 0 ; i < 10 ; i++){
			File file = new File(dataDir+"\\file_"+i+".txt");
			FileOutputStream fos = null;
			try {
				fos = new FileOutputStream(file);
				FileChannel channel = fos.getChannel();
				String line = getDataLine(i,titleList,creatorList);
				ByteBuffer src = Charset.forName("UTF-8").encode(line);
				int length = 0 ;
				while( (length = channel.write(src)) != 0 ){
					System.out.println("写入长度："+length);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				if( fos != null ){
					try {
						fos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	/**
	 * 以|号隔开，数据依次为：id|title|creator|createTime|intNum|doubleNum
	 * @param i
	 * @param titleList 大小为10
	 * @param creatorList 大小为3
	 * @return
	 */
	private static String getDataLine(Integer id, String[] titleList, String[] creatorList){
		StringBuilder sb = new StringBuilder();
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, id*-1);
		sb.append(id).append("|");
		sb.append(titleList[id%10]).append("|");
		sb.append(creatorList[id%3]).append("|");
		sb.append(DateTools.dateToString(cal.getTime(), DateTools.Resolution.SECOND)).append("|");
		sb.append((id+1)*10).append("|");
		sb.append((id+1)*0.2345);
		return sb.toString();
	}
	
	
	
	
	
	public static void main(String[] args) {
		boolean index = true;
		if( !index ){
			generateTestData("D:\\nas\\samp\\lucene\\test01\\data");
		}else{
			String indexDir = "D:\\nas\\samp\\lucene\\test01\\index";
			indexDocs(indexDir,"D:\\nas\\samp\\lucene\\test01\\data",true);
			System.out.println("done!");
		}
	}

}
